# 指定文件编码为UTF-8
# coding: utf-8


# 代码执行流程说明：
# 1. 定义滤波器可视化函数filter_show()
# 2. 初始化并加载预训练的SimpleConvNet
# 3. 可视化网络的第一层卷积滤波器
# 4. 加载Lena测试图像并预处理
# 5. 对图像应用每个滤波器并可视化结果
# 6. 显示所有可视化结果

# 可视化内容说明：
# - 第一部分显示滤波器本身的权重值
# - 第二部分显示这些滤波器在Lena图像上的实际卷积效果
# - 使用4x4网格布局展示16个不同的滤波器

# 注意事项：
# - 需要预先训练好的params.pkl参数文件
# - 需要准备Lena测试图像(灰度图)
# - 滤波器可视化有助于理解CNN学习到的特征
# - 卷积结果展示了滤波器提取的图像特征

"""
apply_filter.py 功能说明：
1. 可视化卷积神经网络学习到的滤波器
2. 展示滤波器在图像上的实际应用效果
3. 使用预训练的简单卷积网络(SimpleConvNet)
4. 包含两个主要可视化功能：
   - 直接显示滤波器权重
   - 显示滤波器在Lena图像上的卷积结果

关键点：
- 使用matplotlib可视化滤波器权重
- 展示卷积操作的实际效果
- 支持灰度图像处理
- 使用网格布局展示多个滤波器
"""

# 导入系统模块
import sys, os
# 添加父目录到系统路径
sys.path.append(os.pardir)
# 导入NumPy数值计算库
import numpy as np
# 导入matplotlib绘图库
import matplotlib.pyplot as plt
# 从simple_convnet导入简单卷积网络类
from simple_convnet import SimpleConvNet
# 从matplotlib.image导入图像读取函数
from matplotlib.image import imread
# 从common.layers导入卷积层类
from common.layers import Convolution

def filter_show(filters, nx=4, show_num=16):
    """
    可视化滤波器权重

    参数:
        filters: 滤波器权重数组(FN, C, FH, FW)
        nx: 每行显示的滤波器数量(默认4)
        show_num: 总共显示的滤波器数量(默认16)
    """
    # 获取滤波器形状
    FN, C, FH, FW = filters.shape
    # 计算需要的行数
    ny = int(np.ceil(show_num / nx))

    # 创建图形并调整子图间距
    fig = plt.figure()
    fig.subplots_adjust(left=0, right=1, bottom=0, top=1, hspace=0.05, wspace=0.05)

    # 绘制每个滤波器的权重
    for i in range(show_num):
        ax = fig.add_subplot(4, 4, i+1, xticks=[], yticks=[])
        ax.imshow(filters[i, 0], cmap=plt.cm.gray_r, interpolation='nearest')

# 初始化简单卷积网络
network = SimpleConvNet(input_dim=(1,28,28),
                        conv_param = {'filter_num':30, 'filter_size':5, 'pad':0, 'stride':1},
                        hidden_size=100, output_size=10, weight_init_std=0.01)

# 加载预训练权重
network.load_params("params.pkl")

# 显示前16个卷积滤波器
filter_show(network.params['W1'], 16)

# 读取并预处理Lena测试图像
img = imread('../dataset/lena_gray.png')
img = img.reshape(1, 1, *img.shape)  # 调整为(1, 1, H, W)格式

# 创建新图形用于显示卷积结果
fig = plt.figure()

# 对前16个滤波器进行可视化
for i in range(16):
    # 获取当前滤波器的权重和偏置
    w = network.params['W1'][i]
    b = 0  # 这里简化处理，不使用偏置

    # 调整权重形状为(1, 1, FH, FW)
    w = w.reshape(1, *w.shape)

    # 创建卷积层并执行前向传播
    conv_layer = Convolution(w, b)
    out = conv_layer.forward(img)
    out = out.reshape(out.shape[2], out.shape[3])  # 调整为2D

    # 添加子图并显示卷积结果
    ax = fig.add_subplot(4, 4, i+1, xticks=[], yticks=[])
    ax.imshow(out, cmap=plt.cm.gray_r, interpolation='nearest')

# 显示所有图形
plt.show()
